package com.akcome.apollo.controller;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.StringUtils;
import org.common.utils.bean.AkResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.PageRequest;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.CookieValue;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import com.akcome.apollo.common.AkResultHelper;
import com.akcome.apollo.common.ApolloConstants;
import com.akcome.apollo.common.AuthUtils;
import com.akcome.apollo.common.CommonUtils;
import com.akcome.apollo.common.SecurityUser;
import com.akcome.apollo.common.TokenHelper;
import com.akcome.apollo.domain.BmpAccount;
import com.akcome.apollo.domain.BmpAccountWallet;
import com.akcome.apollo.domain.BmpNoticeConfig;
import com.akcome.apollo.domain.BmpUser;
import com.akcome.apollo.domain.enums.CoinTypeEnum;
import com.akcome.apollo.domain.enums.PayModeEnum;
import com.akcome.apollo.domain.enums.YesOrNoEnum;
import com.akcome.apollo.domain.resultcode.CommonResultCode;
import com.akcome.apollo.domain.resultcode.UserResultCode;
import com.akcome.apollo.dto.SpeedDataResult;
import com.akcome.apollo.dto.WorkerSpeedResult;
import com.akcome.apollo.service.BmpAccountService;
import com.akcome.apollo.service.BmpAccountWalletService;
import com.akcome.apollo.service.BmpIncomeService;
import com.akcome.apollo.service.BmpNoticeConfigService;
import com.akcome.apollo.service.BmpNoticeService;
import com.akcome.apollo.service.BmpUserService;
import com.akcome.apollo.service.VMiningWorkersService;
import com.akcome.apollo.service.VStatsWorkersHourService;

import io.jsonwebtoken.Claims;

@Controller
@RequestMapping("/user")
public class UserController {
	
	@Autowired
	private AkResultHelper akResultHelper;
	
	@Autowired
	private BmpAccountService bmpAccountService;
	
	@Autowired
	private VMiningWorkersService vMiningWorkersService;
	
	@Autowired
	private VStatsWorkersHourService vStatsWorkersHourService;
	
	@Autowired
	private BmpNoticeConfigService bmpNoticeConfigService;
	
	@Autowired
	private BmpNoticeService bmpNoticeService;
	
	@Value("${accountCountLimit}")
	private int ACCOUNT_COUNT_LIMIT;
	
	@Autowired
	private BmpAccountWalletService bmpAccountWalletService;
	
	@Autowired
	private BmpUserService bmpUserService;
	
	@Autowired
	private BmpIncomeService bmpIncomeService;
	
	@Autowired
	private TokenHelper tokenHelper;
	
	/**
	 * 添加账户
	 * @param name
	 * @return
	 */
	@ResponseBody
	@RequestMapping("/addAccount")
	public AkResult addAccount(String name) throws Exception{
		if(StringUtils.isBlank(name)){
			return akResultHelper.buildFailAkResult(CommonResultCode.PARAM_MISS);
		}
		Pattern regex = Pattern.compile("^[A-Za-z0-9]{4,20}$");
		Matcher matcher = regex.matcher(name);
		if(!matcher.matches()){
			return akResultHelper.buildFailAkResult(UserResultCode.ACCOUNT_FORMAT_ERROR);
		}
		
		Long userId = AuthUtils.getUserId();
		BmpAccount a = bmpAccountService.findByUserIdAndName(userId, name);
		if(null!=a){
			return akResultHelper.buildFailAkResult(UserResultCode.ACCOUNT_USED);
		}
		List<BmpAccount> accounts = bmpAccountService.findByUserId(userId);
		if(null!=accounts &&accounts.size()>ACCOUNT_COUNT_LIMIT){
			return akResultHelper.buildFailAkResult(UserResultCode.ACCOUNT_COUNT_LIMIT);
		}
		
		
		BmpAccount bmpAccount = new BmpAccount();
		bmpAccount.setCreateTime(new Date());
		bmpAccount.setIsEnableNotice(YesOrNoEnum.NO.getCode());
		bmpAccount.setName(name);
		bmpAccount.setUserId(userId);
		bmpAccount.setVersion(0L);
		bmpAccount.setCoinType(CoinTypeEnum.BTC.getCode());
		bmpAccount.setPayMode(PayModeEnum.FPPS.getCode());
		bmpAccount.setUpdateTime(new Date());
		bmpAccountService.save(bmpAccount);
		return akResultHelper.buildSuccessAkResult(null);
	}
	
	@ResponseBody
	@RequestMapping("/speedData")
	public SpeedDataResult speedData(@CookieValue(required = false,value=ApolloConstants.COOKIE_ACCOUNT) Long c_accountId,String type) throws Exception{
		return bmpAccountService.speedData(c_accountId, type);
	}
	
	@ResponseBody
	@RequestMapping("/homeData")
	public Map<String, Object> homeData(@CookieValue(required = false,value=ApolloConstants.COOKIE_ACCOUNT) Long c_accountId,String type) throws Exception{
		Map<String, Object> modelMap = new HashMap<String, Object>();
		modelMap.put("accountId", c_accountId);
		BmpAccount bmpAccount = bmpAccountService.findOne(c_accountId);
		if(null!=bmpAccount){
			modelMap.put("coinType", bmpAccount.getCoinType());
		}
		bmpAccountService.homeUserSetting(modelMap);
		return modelMap;
	}
	
	@ResponseBody
	@RequestMapping("/workers")
	public AkResult workers(@CookieValue(required = false,value=ApolloConstants.COOKIE_ACCOUNT) Long c_accountId,String workerName,String type,int page,int size){
		BmpAccount bmpAccount = bmpAccountService.findOne(c_accountId);
		return akResultHelper.buildSuccessAkResult(vMiningWorkersService.findByPage(c_accountId,workerName,type,bmpAccount.getCoinType(),new PageRequest(page, size)));
	}
	
	/**
	 * 旷工算力
	 * @param c_accountId
	 * @param type
	 * @return
	 * @throws Exception
	 */
	@ResponseBody
	@RequestMapping("/workersSpeed")
	public WorkerSpeedResult workersSpeed(@CookieValue(required = false,value=ApolloConstants.COOKIE_ACCOUNT) Long c_accountId,String type) throws Exception{
		return vStatsWorkersHourService.workersSpeed(c_accountId, type);
	}
	
	/**
	 * 保存通知配置
	 * @param isEnableNotice
	 * @param config
	 * @return
	 */
	@ResponseBody
	@RequestMapping("/saveNoticeConfig")
	public AkResult saveNoticeConfig(@CookieValue(required = false,value=ApolloConstants.COOKIE_ACCOUNT) Long c_accountId,String isEnableNotice,BmpNoticeConfig config){
		return bmpNoticeConfigService.saveNoticeConfig(c_accountId, isEnableNotice, config);
	}
	
	/**
	 * 查询通知
	 * @param c_accountId
	 * @param page
	 * @param size
	 * @return
	 */
	@ResponseBody
	@RequestMapping("/notices")
	public AkResult notices(@CookieValue(required = false,value=ApolloConstants.COOKIE_ACCOUNT) Long c_accountId,int page,int size){
		return akResultHelper.buildSuccessAkResult(bmpNoticeService.findByPage(c_accountId, new PageRequest(page, size)));
	}
	
	/**
	 * 收益记录
	 * @param c_accountId
	 * @param payMode
	 * @param page
	 * @param size
	 * @return
	 */
	@ResponseBody
	@RequestMapping("/income")
	public AkResult income(@CookieValue(required = false,value=ApolloConstants.COOKIE_ACCOUNT) Long c_accountId,String payMode, int page,int size){
		BmpAccount bmpAccount = bmpAccountService.findOne(c_accountId);
		return akResultHelper.buildSuccessAkResult(bmpIncomeService.findByPage(c_accountId, payMode,bmpAccount.getCoinType(),new PageRequest(page, size)));
	}
	
	/**
	 * 添加钱包地址
	 * @param bmpAccountWallet
	 * @return
	 */
	@ResponseBody
	@RequestMapping("/addwalletAddr")
	public AkResult addwalletAddr(BmpAccountWallet bmpAccountWallet){
		return bmpAccountWalletService.addwalletAddr(bmpAccountWallet);
	}
	
	/**
	 * 查询钱包地址
	 * @param accountId
	 * @return
	 */
	@ResponseBody
	@RequestMapping("/walletAddrs")
	public AkResult walletAddrs(Long accountId){
		return akResultHelper.buildSuccessAkResult(bmpAccountWalletService.findByAccountId(accountId));
	}
	
	/**
	 * 删除账户
	 * @param accountId
	 * @return
	 */
	@ResponseBody
	@RequestMapping("/delAccount")
	public AkResult delAccount(Long accountId){
		return bmpAccountService.delete(accountId);
	}
	
	/**
	 * 删除钱包地址
	 * @param walletId
	 * @return
	 */
	@ResponseBody
	@RequestMapping("/delWalletAddr")
	public AkResult delWalletAddr(Long walletId){
		return bmpAccountWalletService.delete(walletId);
	}
	
	/**
	 * 切换币种
	 * @param walletId
	 * @return
	 */
	@ResponseBody
	@RequestMapping("/editCoin")
	public AkResult editCoin(Long walletId,Long accountId){
		return bmpAccountWalletService.editCoin(walletId,accountId);
	}
	
	
	
	/**
	 * 修改登录密码
	 * @param password
	 * @param newpassword1
	 * @param newpassword2
	 * @return
	 */
	@ResponseBody
	@RequestMapping("/editPwd")
	public AkResult editPwd(String password,String newpassword1,String newpassword2,HttpServletRequest request,HttpServletResponse response){
		
		if(!newpassword1.equals(newpassword2)){
			return akResultHelper.buildFailAkResult(UserResultCode.NEW_PWD_DIFF);
		}
		
		//验证密码格式
		if(!CommonUtils.checkPwd(newpassword1)){
			return akResultHelper.buildFailAkResult(UserResultCode.PWD_ERROR);
		}
		
		Long userId = AuthUtils.getUserId();
		BmpUser bmpUser = bmpUserService.findOne(userId);
		BCryptPasswordEncoder bc = new BCryptPasswordEncoder(4);
		if(!bc.matches(password, bmpUser.getPassword())){
			return akResultHelper.buildFailAkResult(UserResultCode.OLD_PWD_FAIL);
		}
		
		bmpUser.setPassword(bc.encode(newpassword1));
		bmpUserService.save(bmpUser);
		SecurityContextHolder.getContext().setAuthentication(null);
		Cookie[] cookies = request.getCookies();
        if (null!=cookies) {
            for(Cookie cookie : cookies){
                //就将value设置为null，将存活时间设置为0，再替换掉原cookie，这样就相当于删除了。
                cookie.setValue(null);
                cookie.setMaxAge(0);
                cookie.setPath("/");
                response.addCookie(cookie);
            }
        }
		
		return akResultHelper.buildSuccessAkResult(null);
		
	}
	/**
	 * 绑定/修改手机
	 * @param userId
	 * @param smsCode
	 * @return
	 */
	@ResponseBody
	@RequestMapping("/bindMobile")
	public AkResult registerMobile(Long userId,String mobile,String smsCode,String callCode,HttpServletRequest request){
		Claims claims = tokenHelper.getTokenClaims(ApolloConstants.COOKIE_SMS_CODE,request);
		if(null==claims){
			//短信验证码已经失效
			return akResultHelper.buildFailAkResult(UserResultCode.SMS_CODE_INVALID);
		}
		if(callCode.equals(claims.get(ApolloConstants.PARAM_CALL_CODE, String.class)) &&
				mobile.equals(claims.get(ApolloConstants.PARAM_MOBILE, String.class)) &&
				smsCode.equals(claims.get(ApolloConstants.PARAM_SMS_CODE, String.class))){
			//短信验证通过
			BmpUser bmpUser = bmpUserService.findOne(userId);
			bmpUser.setMobile(mobile);
			bmpUser.setCallCode(callCode);
			bmpUser = bmpUserService.save(bmpUser);
			
			//更新会话
			SecurityUser userDetails = new SecurityUser(
					bmpUser.getId(),
					bmpUser.getEmail(),
					bmpUser.getPassword(),
					bmpUser.getMobile(),
					bmpUser.getLastPasswordReset(),
                    AuthorityUtils.commaSeparatedStringToAuthorityList(ApolloConstants.ROLE_USER),
                    bmpUser.getEnabled().equals(YesOrNoEnum.YES.getCode())
            );
			// 生成通过认证
			UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
			authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
			// 将权限写入本次会话
			SecurityContextHolder.getContext().setAuthentication(authentication);
			
		}else{
			//短信验证码错误
			return akResultHelper.buildFailAkResult(UserResultCode.SMS_CODE_FAIL);
		}
		
		return akResultHelper.buildSuccessAkResult(null);
	}
	
}
